package com.hz.winnie.demands.common;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.MethodParameter;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;

import com.hz.winnie.demands.annotation.CookieSessionIn;
import com.hz.winnie.demands.annotation.CookieSessionOut;
import com.hz.winnie.demands.utils.CookieSessionUtil;

/**
 * 
 * @description CookieSession注解的解决方案
 */
public class CookieSessionArgumentResolver implements WebArgumentResolver,
	ModelAndViewResolver {

    private CookieSessionUtil cookieSessionUtil;

    public void setCookieSessionUtil(CookieSessionUtil cookieSessionUtil) {
	this.cookieSessionUtil = cookieSessionUtil;
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter,
	    NativeWebRequest webRequest) throws Exception {
	CookieSessionIn in = methodParameter
		.getMethodAnnotation(CookieSessionIn.class);
	if (in == null || !isRightParam(in, methodParameter)) {
	    // 没有CookieSessionIn注解，或者不是该参数
	    return WebArgumentResolver.UNRESOLVED;
	}
	// 被标注为CookieSessionIn的参数
	// 先从请求属性中取，如果不存在则从cookie中取，以免多次解析cookie
	String name = in.value();
	Object sessionObject = webRequest.getAttribute(name,
		RequestAttributes.SCOPE_REQUEST);
	if (sessionObject == null) {
	    Class<?> type = methodParameter.getParameterType();
	    HttpServletRequest request = webRequest
		    .getNativeRequest(HttpServletRequest.class);
	    sessionObject = cookieSessionUtil.getObjectFromCookieSession(name,
		    type, request);
	    if (sessionObject != null) {
		webRequest.setAttribute(name, sessionObject,
			RequestAttributes.SCOPE_REQUEST);
	    }
	}
	return sessionObject;
    }

    @Override
    @SuppressWarnings("unchecked")
    public ModelAndView resolveModelAndView(Method handlerMethod,
	    Class handlerType, Object returnValue,
	    ExtendedModelMap implicitModel, NativeWebRequest webRequest) {
	if (handlerMethod.isAnnotationPresent(CookieSessionOut.class)) {
	    CookieSessionOut annotation = handlerMethod
		    .getAnnotation(CookieSessionOut.class);
	    String name = annotation.value();
	    // 这里删除掉，否则会和request属性中内容同名导致异常
	    Object object = implicitModel.remove(name);
	    // 写cookie，如果object为null，则会删除cookie
	    saveOrClearSession(name, object, webRequest);
	}
	return ModelAndViewResolver.UNRESOLVED;
    }

    private void saveOrClearSession(String name, Object object,
	    NativeWebRequest webRequest) {
	HttpServletResponse response = webRequest
		.getNativeResponse(HttpServletResponse.class);
	if (object == null) {
	    // 删除request属性
	    webRequest.removeAttribute(name, RequestAttributes.SCOPE_REQUEST);
	    cookieSessionUtil.expireCookieSession(name, response);
	} else {
	    // 放入request属性中，覆盖原来的值
	    webRequest.setAttribute(name, object,
		    RequestAttributes.SCOPE_REQUEST);
	    cookieSessionUtil.saveObjectToCookieSession(name, object, response);
	}
    }

    private boolean isRightParam(CookieSessionIn in,
	    MethodParameter methodParameter) {
	String paramName = "".equals(in.param()) ? in.value() : in.param();
	return paramName.equals(methodParameter.getParameterName());
    }
}
